package com.kongjs.application.util;

import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class IpUtil implements InitializingBean, DisposableBean {
    private static final String dbPath = "ip2region.xdb";
    private static Searcher searcher;


    public static String getRegion(String ip) {
        try {
            if (StringUtils.hasText(ip) && !ip.equals("0:0:0:0:0:0:0:1")) {
                if (!ObjectUtils.isEmpty(searcher)) {
                    return searcher.search(ip);
                }
            }
        } catch (Exception e) {
            log.error("根据IP获取区域异常 {}", ip, e);
        }
        return null;
    }

    public static void main(String[] args) {
        String dbPath = "ip2region.xdb file path";

        // 1、从 dbPath 加载整个 xdb 到内存。
        byte[] cBuff;
        try {
            cBuff = Searcher.loadContentFromFile(dbPath);
        } catch (Exception e) {
            System.out.printf("failed to load content from `%s`: %s\n", dbPath, e);
            return;
        }

        // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
        Searcher searcher;
        try {
            searcher = Searcher.newWithBuffer(cBuff);
        } catch (Exception e) {
            System.out.printf("failed to create content cached searcher: %s\n", e);
            return;
        }
        String ip = "1.2.3.4";
        // 3、查询
        try {

            long sTime = System.nanoTime();
            String region = searcher.search(ip);
            long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));
            System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);
        } catch (Exception e) {
            System.out.printf("failed to search(%s): %s\n", ip, e);
        }

        // 4、关闭资源 - 该 searcher 对象可以安全用于并发，等整个服务关闭的时候再关闭 searcher
        // searcher.close();

        // 备注：并发使用，用整个 xdb 数据缓存创建的查询对象可以安全的用于并发，也就是你可以把这个 searcher 对象做成全局对象去跨线程访问。
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        byte[] bytes = null;
        try {
            String dir = System.getProperty("user.dir");
            Path path = Path.of(dir, dbPath);
            if (Files.exists(path)) {
                bytes = Searcher.loadContentFromFile(path.toString());
                log.info("加载xdb成功,{}", path);
            } else {
                log.info("加载xdb路径不存在,{}", path);
            }
        } catch (IOException e) {
            log.error("加载xdb异常", e);
        }
        if (!ObjectUtils.isEmpty(bytes)) {
            try {
                searcher = Searcher.newWithBuffer(bytes);
                log.info("加载xdb缓存成功");
            } catch (IOException e) {
                log.error("加载xdb缓存异常", e);
            }
        }
    }

    @Override
    public void destroy() throws Exception {
        try {
            if (!ObjectUtils.isEmpty(searcher)) {
                searcher.close();
            }
        } catch (IOException ignored) {
        }
    }
}
